home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / biblio / bibtex / utils / bibclean / vmswild.c < prev    next >
C/C++ Source or Header  |  1992-11-14  |  32KB  |  1,058 lines

  1. /* -*-C-*- vmswild.c */
  2. /*-->vmswild*/
  3. /**********************************************************************/
  4. /****************************** vmswild *******************************/
  5. /**********************************************************************/
  6.  
  7. #include "os.h"
  8.  
  9. #if 0            /* BEGIN COMMENT SECTION */
  10.  
  11. /* Compile with TEST defined to create a stand-alone test program */
  12.  
  13.  
  14. /***********************************************************************
  15. ** [09-Mar-1990]
  16. ** Edit by  Nelson H. F. Beebe <Beebe@science.utah.edu>
  17. ** Overhaul to meet these objectives:
  18. **
  19. **    (1) If a file is in the current directory, the device and
  20. **    directory specification is stripped from the file name.
  21. **
  22. **    (2) Convert all file names in argv[] to lower case.
  23. **
  24. **    (3) If a generation number was specified in the command-line
  25. **    file name, as indicated by the presence of a semicolon in the
  26. **    wildcard specification, preserve generation numbers in the
  27. **    output; otherwise, eliminate them, since the files must
  28. **    correspond to the highest generation.
  29. **
  30. **    (4) If a filename ends in a dot, remove it ("foo." -> "foo").
  31. **
  32. **      (5) Reorder routines alphabetically, and supply Standard C 
  33. **      function prototype declarations.
  34. **
  35. **    (6) Make all functions and global variables static (private),
  36. **      except cmd_lin(), so they do not interfere with user-defined
  37. **      values outside this file.
  38. **
  39. **    (7) Remove prompting for missing arguments.
  40. **
  41. ** These changes result in a shorter command line, which is important
  42. ** when the names are used to build other commands (e.g. in vcc),
  43. ** because VAX VMS has a very limited command line buffer size.  They
  44. ** also match what UNIX programs get from the shell command line
  45. ** expansion; this is important for programs like gawk where the
  46. ** filename may be used by the program.  UNIX programs never prompt
  47. ** for arguments, and they shouldn't do so either when ported to VAX
  48. ** VMS.  New functions added are expand_logical() and
  49. ** normalize_filename().  The body of nxt_wld() has been completely
  50. ** rewritten.
  51. **
  52. ************************************************************************
  53. ** PDVI:VMSWILD.C, Sat Oct  1 15:59:31 1988
  54. ** Edit by  Nelson H. F. Beebe <Beebe@science.utah.edu>
  55. ** Fix erroneous leading comments, change initialization of OPoption
  56. ** so that arguments of form "{foo}" (e.g. for awk) are not lost.
  57. **
  58. ************************************************************************
  59. ** Original version:
  60. **  4-Mar-88 19:08:58-MST,26262;000000000000
  61. ** Return-Path: <news@cs.utah.edu>
  62. ** Received: from cs.utah.edu by SCIENCE.UTAH.EDU with TCP;
  63. **     Fri 4 Mar 88 19:08:46-MST
  64. ** Received: by cs.utah.edu (5.54/utah-2.0-cs)
  65. **     id AA20734; Fri, 4 Mar 88 19:08:52 MST
  66. ** From: news@cs.utah.edu (Netnews Owner)
  67. ** Reply-To: ERICMC%usu.BITNET@CC.UTAH.EDU (Eric McQueen)
  68. ** To: comp-os-vms@cs.utah.edu
  69. ** Subject: RE: Wild card expansion under VAX11-C: Code Wanted
  70. ** Message-Id: <8803041943.AA24229@jade.berkeley.edu>
  71. ** Date: 4 Mar 88 04:59:00 GMT
  72. ** Sender: daemon@ucbvax.berkeley.edu
  73. **
  74. ** (sorry for the previous abbreviated copy of this)
  75. **
  76. ** In article <5361@ames.arpa> woo@pioneer.UUCP (Alex Woo) writes:
  77. ** > How does one expand wildcards in command line arguments in
  78. ** > VAX11-C under VMS?
  79. **
  80. ** I have a tool for C programmers using VMS, especially those porting
  81. ** facilities from Un*x.  It prompts for command line arguments (unless
  82. ** you have already specified some via a "foreign command" or MCR),
  83. ** expands file wildcards found on the command line, and redirects
  84. ** 'stdin' or 'stdout'.  Here is a sample use:
  85. **
  86. ** int
  87. ** main( argc, argv )
  88. **   int argc;
  89. **   char **argv;
  90. ** {
  91. **   !* local variables *!
  92. ** #ifdef VMS     !* Or whatever the Standard C-conforming word will be *!
  93. **     extern char **cmd_lin();
  94. **
  95. **     argv = cmd_lin( "", &argc, argv );
  96. **     !* The first argument provides misc. options (not currenly used). *!
  97. ** #endif !* VMS *!
  98. **     !* your routine *!
  99. ** }
  100. **
  101. ** $ run grep
  102. ** _command_line_arguments: -i STOP *.for
  103. **
  104. ** The source is 40 blocks (600 lines) so I am not sure that I should
  105. ** post the actual source in this group, but I have (see below).  If you
  106. ** are interested, please look through the documentation, try it out,
  107. ** and send any significant comments, suggestions, useful peices of
  108. ** code, etc. to one of the addresses below.    I will post summaries to
  109. ** comp.os.vms/INFO-VAX and comp.lang.c/INFO-C.  Please excuse the
  110. ** "lived-in" look of the code but I am still working on this thing so
  111. ** this is mearly the last debugged version I have.
  112. **
  113. ** ---
  114. ** Eric Tye McQueen      Mathematics Department    Also at (after some
  115. ** ericmc@usu.bitnet      Utah State University          time in March[June?!]):
  116. ** (801) 753-4683      Logan, Utah  84322-3900    ericmc@usu.usu.edu
  117. **
  118. **    UUCP:  ...{psuvax1,uunet}!usu.bitnet!ericmc         "Doodle doodle dee"
  119. **    Arpa:  ericmc%usu.bitnet@cunyvm.cuny.edu          "wubba wubba wubba."
  120. **
  121. ** +------------------------------- cmdlin.c -------------------------------+
  122. ***********************************************************************/
  123.  
  124. /***********************************************************************
  125.  * cmdlin.c -- Un*x-style command line processing for VMS.  (V2.0,  3-Mar-1988)
  126.  *    Copyright (C) 1988 Eric Tye McQueen
  127.  * Emulates Un*x-style command line options in VAX C programs:
  128.  *    - Allows entry of command line arguments after the program starts:
  129.  *    The easiest way to run a program in VMS (the RUN command) does not
  130.  *    allow for specification of command-line arguments while other methods
  131.  *    that do allow arguments won't interpret the arguments in a very Un*x-
  132.  *    like manner.  If no arguments are specified (other than the program
  133.  *    name which is supplied by VAX C), we prompt for arguments from
  134.  *    SYS$COMMAND and try to interpret them as Un*x would.
  135.  *    - Expands any filename wildcards found in the command line arguments:
  136.  *    C programs that process files are usually written to accepts several
  137.  *    filenames, one name per argument.  Un*x environments expand filename
  138.  *    wildcards specified on the command line to the names of all matching
  139.  *    files and pass these names to the program.  This routine does this
  140.  *    since VMS will not.  VMS wildcards and filenames are supported, NOT
  141.  *    Un*x-style wildcards and filenames (this has its good and bad points).
  142.  *    - Supports simple C-shell-style standard I/O redirection (`<', `>', `>>',
  143.  *    `>&', and `>>&').
  144.  *    - In the future support can be added for strings and quoting of charac-
  145.  *    ters (`\', "'", `"'), symbol substitution (`$'), parallel processing
  146.  *    and pipes (`||', `&&', etc.), etc.
  147.  *
  148.  * Currently supported:
  149.  *    All VMS wildcards (`*', `%', and `...').
  150.  *    Both VMS and Un*x-style file names.
  151.  *    I/O redirection via `<', `>', `>>', `>&', and `>>&'
  152.  *        (watch out for people who use `<' and `>' for directory names)
  153.  * Reasonable to add support for:
  154.  *    Specification of cmd_lin() options between `{' and `}'.
  155.  *    Continuation lines via \ at end of line.
  156.  *    Inclusion of spaces (and newlines) into arguments via ' and ".
  157.  *    Substitutions from the VMS symbol table using ${name}.
  158.  *    Using Un*x-style directories (/) with wildcards.
  159.  * Pipe dreams:
  160.  *    Pipes via || and &&.
  161.  *    Un*x-style wildcards like [char-set].
  162.  *        (watch out for people who use `[' and `]' for directory names!!)
  163.  *
  164.  * This files also contains a special demonstartion program.  To use it type:
  165.  *    $ cc cmdlin/define:example
  166.  *    $ link cmdlin,sys$input:/opt
  167.  *    sys$share:vaxcrtl/share
  168.  *    $ run cmdlin
  169.  *
  170.  * Sample use:
  171.  *    ...
  172.  *    int
  173.  *    main( argc, argv )
  174.  *      int argc;
  175.  *      char **argv;
  176.  *    {
  177.  *      ... (definitions)
  178.  *    #ifdef VMS
  179.  *      extern char **cmd_lin();
  180.  *        argv = cmd_lin( "", &argc, argv );
  181.  *    #endif
  182.  *        ... (other statements)
  183.  *    }
  184.  *    ...
  185.  *    $ run grep
  186.  *    _command_line_arguments: -i stop *.for
  187.  *
  188.  *    If you specify something that looks like a VMS wildcard (that contains
  189.  * "*", "%", or "...") but that doesn't match the name of any existing files,
  190.  * cmd_lin() will write "<pattern>: No match." to `stderr'.  If you specify a
  191.  * string containing "*", "%", or "..." that is not a valid VMS file wildcard,
  192.  * cmd_lin() will also write "<pattern>: Invalid file wildcard." to `stderr'.
  193.  * In either case, the original string will be included, unchanged, as a
  194.  * command line argument.
  195.  ***********************************************************************/
  196.  
  197. #endif            /* END COMMENT SECTION */
  198.  
  199. #if 0
  200. static char version[] = /* (Not currently) printed inside "debug" option. */
  201.   "cmd_lin() V2.0, Copyright (C) 1988 Eric Tye McQueen (3-Mar).";
  202. #endif /* 0 */
  203.  
  204. static char rcsid[] = "$Id: vmswild.c,v 1.6 1992/11/15 16:59:38 beebe Exp beebe $";
  205.  
  206. /* $Log: vmswild.c,v $
  207.  * Revision 1.6  1992/11/15  16:59:38  beebe
  208.  * Correct some function declarations converted incompletely during
  209.  * the C++ conversion.  Add some more typecasts, using NULL instead of 0.
  210.  * Remove static attribute from cmd_line() declaration.
  211.  *
  212.  * Revision 1.5  1992/10/08  01:42:01  beebe
  213.  * Update for C++.
  214.  * Modify some comments to avoid confusing preprocessors that
  215.  * parse text lines between #if 0 ... #endif.
  216.  *
  217.  * Revision 1.4  1992/07/10  18:03:46  beebe
  218.  * Add some typecasts.
  219.  *
  220.  * Revision 1.3  1992/03/10  00:33:33  beebe
  221.  * *** empty log message ***
  222.  *
  223.  * Revision 1.2  1992/02/29  19:42:20  beebe
  224.  * Update for version 3.0.114 [29-Feb-1992] following two-month
  225.  * major overhaul and compilation testing on numerous machines.
  226.  *
  227.  * Revision 1.2  1992/02/29  19:42:20  beebe
  228.  * Update for version 3.0.114 [29-Feb-1992] following two-month
  229.  * major overhaul and compilation testing on numerous machines.
  230.  * */ 
  231.  
  232. #ifndef VMS    /* Should be changed to Standard C-conforming name soon. */
  233.  
  234. /* Dummy version of cmd_lin() for non VAX C (nonVMS) systems: */
  235.  
  236. char **
  237. #if STDC
  238. cmd_lin(
  239. char    *opt0,                /* Options specified in `main()' */
  240. int    *ainpc,                /* &main\argc (input and output) */
  241. char    **inpv                /* main\argv (input) */
  242. )
  243. #else /* NOT STDC */
  244. cmd_lin( opt0, ainpc, inpv )
  245. char    *opt0;                /* Options specified in `main()' */
  246. int    *ainpc;                /* &main\argc (input and output) */
  247. char    **inpv;                /* main\argv (input) */
  248. #endif /* STDC */
  249. {
  250.     return( inpv );
  251. }
  252.  
  253. #else  /* VMS */
  254.  
  255. #include <stdio.h>    /* stdin stdout stderr */
  256. #include <ctype.h>    /* iscntrl() isascii() */
  257. #include <errno.h>    /* errno vaxc$errno */
  258.  
  259. #include <stdlib.h>
  260. #include <string.h>
  261.  
  262. typedef     char  bool;        /* Smallest addressable signed data type. */
  263. typedef     unsigned char     uchar;
  264. typedef     unsigned short     ushort;
  265. typedef     unsigned int     uint;
  266. typedef     unsigned long     ulong;
  267.  
  268. #define      odd(stat)   ( (stat) & 1 )
  269.  
  270. /* General VMS descriptor (not as clumsy as $DESCRIPTOR from <descrip.h>): */
  271. struct descr {
  272.     ushort leng;    /* Length of data area (or string). */
  273.     uchar  type;    /* Type of data in area (dsc$k_dtype_t). */
  274.     uchar  class;    /* Class of desctiptor (dsc$k_class_s). */
  275.     char  *addr;    /* Address of start of data area. */
  276. };
  277. globalvalue dsc$k_dtype_t; /* Text (data type) */
  278. globalvalue dsc$k_class_s; /* Static (class) descriptor */
  279.  
  280. /* To allocate a descriptor (dsc) for array of char (arr): */
  281. #define      desc_arr(dsc,arr)    struct descr dsc = \
  282.   { (sizeof arr)-1, dsc$k_dtype_t, dsc$k_class_s, arr }
  283.  
  284. /* To allocate a descriptor (dsc) for null-terminated string (str): */
  285. #define      desc_str(dsc,str)    struct descr dsc = \
  286.   { strlen(str), dsc$k_dtype_t, dsc$k_class_s, str }
  287.  
  288. #define      FNAMSIZ  1024 /* size of filename buffers (+1 for '\0') */
  289. #define      LINSIZ   20480 /* maximum length of command line */
  290.  
  291. /* Options that are set by an argument like "{opt1,!opt2,noopt3,opt4=val}":
  292.  * (none of these are really supported in this release)
  293.  *    help : show possible options then terminate execution.
  294.  *    option : allows options to be specified (default).
  295.  *    expand : expand VMS-style wildcards (default).
  296.  *    prompt [ = string ] : prompt if no arguments are present (default).
  297.  *    append : prompt if some arguments are initially present.
  298.  *    debug : show option changes and final command line arguments.
  299.  *    redirect : allows `<', `>', etc. to be used to redirect `std*'.
  300.  *    unixy : don't return VMS-style device or directory names (default).
  301.  *    lower : convert letters in file specifications to lowercase (default).
  302.  *    device = "never", "different" (default), "always" : show device name.
  303.  *    directory = "never", "different" (default), "always" : show directory.
  304.  *    version = "never", "different" (default), "always" : show version.
  305.  *    `dev':/`path' : Un*x-like alias for device name (ex: "user$disk:/usr").
  306.  * Interactions:
  307.  *    unixy & show device -> show directory
  308.  *    unixy & !device & directory -> directory is relative (../etc)
  309.  *    unixy & !device & directory=always -> default = ./
  310.  */
  311.  
  312. /* Key values for OTfreq options (device, directory, and version): */
  313. enum { never=0, diff, always };
  314.  
  315. /* Current values of all options: */
  316. #if 0
  317. char    *OPprompt    = "_command_line_arguments: ";
  318. #else /* 1 */
  319. char    *OPprompt    = (char*)NULL;
  320. #endif /* 0 */
  321.  
  322. #if 0
  323. /* Disable; otherwise an awk option string like "{print $0}" disappears. */
  324. static char    *OPoption    = "{}";
  325. #else  /* NOT 0 */
  326. static char    *OPoption    = "";
  327. #endif /* 0 */
  328.  
  329. static bool     OPexpand    = 1;
  330. static bool     OPappend    = 0;
  331. static bool     OPdebug    = 0;
  332. static bool     OPredir    = 1;
  333. static bool     OPunixy    = 1;
  334. static bool     OPlower    = 1;
  335. static bool     OPdevice    = diff;
  336. static bool     OPdirect    = diff;
  337. static bool     OPversion    = diff;
  338.  
  339. char        **cmd_lin(char *opt0,int *ainpc,char **inpv);
  340.  
  341. /* Private functions */
  342. static char    **add_arg(char *arg, int *acnt, char **ptrs);
  343. static uint    crelnm(char *table, char *name, char *value);
  344. static void    *emalloc(unsigned siz);
  345. static void    *erealloc(void *ptr, unsigned siz);
  346. static char    *expand_logical(char *logname);
  347. static bool    iswild(char *name);
  348. static char    *nameonly(char *file);
  349. static char    *normalize_filename(char *filename);
  350. static char    *nxt_wld(char *wild);
  351. static char    **parse_opt(int *ainpc,char **inpv);
  352. static char    **read_cmd_lin(int *ainpc,char **inpv);
  353. static char    *read_w_prompt(char *prompt, char *buff, int size);
  354. static char    **redir(int *ainpc,char **inpv,FILE *fp,char *io,
  355.             char *tok,char *lnm,char *acc);
  356. static char    **redirin(int *ainpc,char **inpv);
  357. static char    **redirout(int *ainpc,char **inpv);
  358. static void    sigvms(uint stat);
  359. static char    *strsub(char *str, char *sub);
  360.  
  361. #ifdef TEST
  362. static void    dump(char *str);
  363. int        main(int argc,char **argv);
  364. #endif /* TEST */
  365.  
  366. char **
  367. #if STDC
  368. cmd_lin(
  369. char    *opt0,                /* Options specified in `main()' */
  370. int    *ainpc,                /* &main\argc (input and output) */
  371. char    **inpv                /* main\argv (input) */
  372. )
  373. #else /* NOT STDC */
  374. cmd_lin( opt0, ainpc, inpv )        /* returns new value for main\argv */
  375. char    *opt0;                /* Options specified in `main()' */
  376. int    *ainpc;                /* &main\argc (input and output) */
  377. char    **inpv;                /* main\argv (input) */
  378. #endif /* STDC */
  379. {
  380.     int endc;    /* `endc' and `endv' will be `argc' and `argv' for main() */
  381.     char **endv = add_arg((char*)NULL,&endc,(char**)NULL);
  382.                     /* Initialize `add_arg()' structures */
  383.     char **xtra = 0;    /* So we can free() what read_cmd_lin() may allocate */
  384.     char *cp;
  385.  
  386.     if(  OPoption[0] == *opt0  )
  387.         inpv = parse_opt( ainpc, inpv );
  388. #ifdef DEBUG
  389.     else if(  *opt0     )
  390.     {
  391.         globalvalue ss$abort;
  392.         fprintf( stderr, "%s (%s) %s.\n", "Invalid options string",
  393.             opt0, "specified in `main()'" );
  394.         exit( ss$abort );
  395.     }
  396. #endif /* DEBUG */
  397.     if(  *ainpc  )
  398.     {            /* Process `argv[0]', the program name: */
  399.         if(  OPunixy  ) /* Remove VMS device/dir/version: */
  400.         *inpv = nameonly( *inpv );    /* (and ".ext") */
  401.         endv = add_arg( *inpv, &endc, endv );
  402.         --*ainpc;
  403.         ++inpv;
  404.     }
  405.     else        /* (Impossible?)  No `argv[0]' so make one up: */
  406.         endv = add_arg( "Me", &endc, endv );
  407.     if (  OPappend  ||  ( !*ainpc && OPprompt )  )
  408.         xtra = inpv = read_cmd_lin( ainpc, inpv );
  409.     while (    *ainpc    )
  410.     {
  411.         if(  OPoption  &&  OPoption[0] == **inpv  )
  412.             inpv = parse_opt( ainpc, inpv );
  413.         else if(  OPredir  &&     '<' == **inpv    )
  414.             inpv = redirin( ainpc, inpv );
  415.         else if(  OPredir  &&     '>' == **inpv    )
  416.             inpv = redirout( ainpc, inpv );
  417.         else if(  OPexpand  &&  iswild( *inpv )  )
  418.         {
  419.             if(  ( cp = nxt_wld(*inpv) )  )
  420.             {
  421.                 do
  422.                 {
  423.                 endv = add_arg( cp, &endc, endv );
  424.                 } while(  ( cp = nxt_wld(*inpv) )  );
  425.             }
  426.             else
  427.             {
  428.                 fprintf( stderr, "%s: No match.\n", *inpv );
  429.                 endv = add_arg( *inpv, &endc, endv );
  430.             }
  431.         }
  432.         else
  433.             endv = add_arg( *inpv, &endc, endv );
  434.         --*ainpc;
  435.         ++inpv;
  436.     }
  437.     if (  xtra  )    /* An extra block of pointers was malloc()ed */
  438.         free( xtra );
  439.     *ainpc = endc;
  440.  
  441.     return( endv );
  442. }
  443.  
  444. /**********************************************************************/
  445. /*                     Private functions                              */
  446. /**********************************************************************/
  447.  
  448. /* Builds argc,argv type lists of strings: */
  449. static char **
  450. #if STDC
  451. add_arg(
  452.   char *arg,    /* Argument to be added to the argument list */
  453.   int *acnt,    /* Number of arguments currently in the argument list */
  454.   char **ptrs    /* Array of pointers to the arguments */
  455. )
  456. #else /* NOT STDC */
  457. add_arg( arg, acnt, ptrs )
  458.   char *arg;    /* Argument to be added to the argument list */
  459.   int *acnt;    /* Number of arguments currently in the argument list */
  460.   char **ptrs;    /* Array of pointers to the arguments */
  461. #endif /* STDC */
  462. {
  463. # define ARGRP 64    /* number of string pointers allocated at a time */
  464.     if(  !ptrs  ) { /* Initialize a new argument list: */
  465.       char **v = emalloc( ARGRP * sizeof(char *) );
  466.         *acnt = 0;
  467.         v[0] = 0;
  468.         return( v );
  469.     }
  470.     if(  0 == (*acnt+1) % ARGRP  ) /* Need more space for pointers */
  471.         ptrs = erealloc( ptrs, (*acnt+1+ARGRP) * sizeof(char *) );
  472.     ptrs[*acnt] = arg;
  473.     ptrs[++*acnt] = (char*)NULL;
  474.     return( ptrs );
  475. }
  476.  
  477. /* Creates a logical name. */
  478. static uint                /* Returns a VMS condition value. */
  479. #if STDC
  480. crelnm(
  481.   char *table,
  482.   char *name, 
  483.   char *value
  484. )
  485. #else /* NOT STDC */
  486. crelnm( table, name, value )
  487.   char *table;
  488.   char *name;
  489.   char *value;
  490. #endif /* STDC */
  491. {
  492.   desc_str( tdsc, table );
  493.   desc_str( ndsc, name );
  494.   struct itemstr {
  495.     ushort buflen, type;
  496.     char *addr;
  497.     ushort *retlen;
  498.     uint end;
  499.   } itemrec;
  500.   /* globalvalue psl$k_user; */ /* Change this to "#include psldef". */
  501.   uchar mode = 3 /* psl$k_user */;
  502.   extern uint sys$crelnm();
  503.   /* globalvalue lnm$_string; */ /* Change this to "#include lnmdef". */
  504.     itemrec.type    = 2 /* lnm$_string */;
  505.     itemrec.buflen    = strlen(value);
  506.     itemrec.addr    = value;
  507.     itemrec.retlen    = (ushort *) 0;
  508.     itemrec.end    = 0;
  509.     return(     sys$crelnm( 0, &tdsc, &ndsc, &mode, &itemrec )     );
  510. }
  511.  
  512. /* Same as malloc() except never returns NULL. */
  513. static void *
  514. #if STDC
  515. emalloc(
  516.   unsigned siz
  517. )
  518. #else /* NOT STDC */
  519. emalloc( siz )
  520.   unsigned siz;
  521. #endif /* STDC */
  522. {
  523.   globalvalue ss$_insfmem;    /* Insufficient dynamic memory error */
  524.   register void *p = malloc( siz );
  525.     if(  !p     )    /* Don't try to recover after allocating too much: */
  526.         sys$exit( ss$_insfmem );    /* Don't recover */
  527.     return( p );
  528. }
  529.  
  530. /* Same as realloc() except never returns NULL. */
  531. static void *
  532. #if STDC
  533. erealloc(
  534.   void *ptr,
  535.   unsigned siz
  536. )
  537. #else /* NOT STDC */
  538. erealloc( ptr, siz )
  539.   void *ptr;
  540.   unsigned siz;
  541. #endif /* STDC */
  542. {
  543.   globalvalue ss$_insfmem;    /* Insufficient dynamic memory error */
  544.   register void *p = realloc( ptr, siz );
  545.     if(  !p     )    /* Don't try to recover after allocating too much: */
  546.         sys$exit( ss$_insfmem );    /* Don't recover */
  547.     return( p );
  548. }
  549.  
  550. static char*
  551. #if STDC
  552. expand_logical(
  553. char    *logname
  554. )
  555. #else /* NOT STDC */
  556. expand_logical(logname)        /* return recursively expanded logical name */
  557. char    *logname;
  558. #endif /* STDC */
  559. {
  560.     char    *p;
  561.     char    *colon;
  562.  
  563.     colon = strchr(logname,':'); /* trim string before colon for getenv() */
  564.     if (colon)
  565.     *colon = '\0';
  566.     p = getenv(logname);
  567.     if (colon)
  568.     *colon = ':';
  569.  
  570.     return ((p == (char*)NULL) ? logname : expand_logical(p));
  571. }
  572.  
  573.  
  574. static bool    /* Returns 1 if `name' looks like a wild-carded file name. */
  575. #if STDC
  576. iswild(
  577.   char *name
  578. )
  579. #else /* NOT STDC */
  580. iswild( name )
  581.   char *name;
  582. #endif /* STDC */
  583. {
  584.     return(strchr(name,'*')     ||  strchr(name,'%')  ||  strsub(name,"..."));
  585. }
  586.  
  587. /* Usually used to simplify argv[0]. */
  588. static char *
  589. #if STDC
  590. nameonly(
  591.   char *file
  592. )
  593. #else /* NOT STDC */
  594. nameonly( file )
  595.   char *file;
  596. #endif /* STDC */
  597. {
  598.   char *cp = file, *tp;
  599. #ifdef VMS
  600.     tp = strrchr(cp,']');        /* Skip directory */
  601.     tp = tp ? tp+1 : cp;
  602.     cp = strrchr(tp,'>');        /* Skip alternate form of directory */
  603.     cp = cp ? cp+1 : tp;
  604.     tp = strrchr(cp,':');        /* Skip device and/or node */
  605.     tp = tp ? tp+1 : cp;
  606.     cp = tp;
  607.     if(  tp = strchr(cp,';')  )    /* Remove version number */
  608.         *tp = '\0';
  609.     if(  tp = strchr(cp,'.')  )    /* Remove extension and/or... */
  610.         *tp = '\0';        /*  alternate form for version */
  611. #else  /* NOT VMS */
  612.     /* cp = strrchrb(cp,'/'); may be useful on other than MS-DOS */
  613. #ifdef MSDOS    /* Like this would ever be run under MS-DOS! */
  614.     tp = strrchr(cp,'/');        /* Skip Un*x path */
  615.     tp = tp ? tp+1 : cp;
  616.     cp = strrchr(tp,'\\');        /* Skip MS-DOS path */
  617.     cp = cp ? cp+1 : tp;
  618.     if(  tp = strchr(cp,'.')  )
  619.         *tp = '\0';        /* Remove extension */
  620. #endif /* MSDOS */
  621. #endif /* VMS */
  622.     return( cp );
  623. }
  624.  
  625. static char*
  626. #if STDC
  627. normalize_filename(
  628. char    *filename        /* with logical names expanded */
  629. )
  630. #else /* NOT STDC */
  631. normalize_filename(filename)    /* return lower-case copy of normalized name */
  632. char    *filename;        /* with logical names expanded */
  633. #endif /* STDC */
  634. {
  635.     char    *logname;
  636.     char    *p;
  637.     char    *q;
  638.  
  639.     p = strchr(filename,':');    /* do we have a logical name? */
  640.     if (p != (char*)NULL)
  641.     {                /* yes, have to translate it interatively */
  642.     logname = expand_logical(filename);
  643.     q = emalloc(strlen(p+1) + strlen(logname) + 1);
  644.     (void)strcpy(q,logname);
  645.     (void)strcat(q,p+1);
  646.     }
  647.     else            /* no, just copy bare file name */
  648.     q = strcpy(emalloc(strlen(filename)),filename);
  649.  
  650.     for (p = q ; *p; ++p)    /* convert filename to lowercase */
  651.     *p = isupper(*p) ? tolower(*p) : *p;
  652.  
  653.                 /* remove remnants of rooted logical names */
  654.     for (p = strsub(q,".]["); p; p = strsub(q,".]["))
  655.     (void)strcpy(p+1,p+3);
  656.  
  657.     return (q);
  658. }
  659.  
  660.  
  661. /* Returns the next file name matching the specified wildcard. */
  662. static char *    /* Returns a pointer to an malloc()ed expanded filename */
  663. #if STDC
  664. nxt_wld(
  665.   char    *wild    /* Wildcard to be expanded. */
  666. )
  667. #else /* NOT STDC */
  668. nxt_wld( wild ) /* Returns 0 if all matching filenames have been returned. */
  669.   char    *wild;    /* Wildcard to be expanded. */
  670. #endif /* STDC */
  671. {
  672.     desc_str( wlddsc, wild );    /* VMS descriptor of wildcard string. */
  673.     static uint cntxt = 0;    /* Context of wildcard search. */
  674.     uint stat;            /* Status returned by lib$* services. */
  675.     uint two = 2;        /* Flags to be passed by reference. */
  676.     char file[FNAMSIZ];        /* Buffer to hold expanded file name. */
  677.     desc_arr( fildsc, file );    /* VMS descriptor of buffer. */
  678.     extern uint lib$find_file(), lib$find_file_end();    /* Library services. */
  679.     globalvalue rms$_fnf, rms$_nmf, rms$_syn;    /* Possible statuses. */
  680.     static char* cwd = (char*)NULL;
  681.     static int lencwd = 0;
  682.     char    *colon;
  683.     char    *logname;
  684.     char    *newcwd;
  685.     char    *p;
  686.     char    *q;
  687.  
  688.     if (cwd == (char*)NULL)        /* true only on first call */
  689.     {
  690.     cwd = (char*)getcwd((char*)NULL,FNAMSIZ);
  691.     lencwd = (cwd == (char*)NULL) ? 0 : strlen(cwd);
  692.     if (lencwd > 0)
  693.     {
  694.         newcwd = normalize_filename(cwd);
  695.         free(cwd);
  696.         cwd = newcwd;
  697.         lencwd = strlen(cwd);
  698.     }
  699.     }
  700.  
  701.     stat = lib$find_file( &wlddsc, &fildsc, &cntxt, 0, 0, 0, &two );
  702.     if (  rms$_syn == stat )
  703.     {                /* File syntax error: */
  704.     fprintf( stderr, "%s: Invalid file wildcard.\n", wild );
  705.     }
  706.     else if (  rms$_fnf != stat  &&  rms$_nmf != stat )
  707.     {
  708.     /* Not "file not found" (1st try)
  709.      * nor "no more files" (later tries): */
  710.     sigvms( stat ); /* Display non-trivial status messages. */
  711.     }
  712.     if(  !odd(stat)     )
  713.     {                /* Search didn't work: */
  714.     sigvms( lib$find_file_end( &cntxt ) );
  715.     return( 0 );
  716.     }
  717.     while (' ' == file[fildsc.leng-1]) /* Remove trailing spaces: */
  718.     --fildsc.leng;
  719.     file[fildsc.leng] = '\0';
  720.  
  721.     p = normalize_filename(file);
  722.     (void)strcpy(file,p);
  723.     free(p);
  724.     if (strsub(wild,";") == (char*)NULL) /* strip generation numbers too */
  725.     {
  726.     p = strrchr(file,';');
  727.     if (p != (char*)NULL)
  728.         *p = '\0';
  729.     else
  730.         p = strrchr(file,'\0');
  731.     if (p[-1] == '.')    /* trim final dot too */
  732.         p[-1] = '\0';
  733.     }
  734.     fildsc.leng = strlen(file);
  735.  
  736.     /* Strip off current working directory, if present. */
  737.     if ((lencwd > 0) && (strncmp(cwd,file,lencwd) == 0))
  738.     {
  739.     (void)strcpy(file,&file[lencwd]);
  740.     fildsc.leng -= lencwd;
  741.     }
  742.  
  743.     return( strcpy( emalloc((unsigned)fildsc.leng+1), file )  );
  744. }
  745.  
  746. /* Accepts argument beginning "{" and parses the options listed before the
  747.  * closing "}". */
  748. static char **        /* Returns new value of `inpv'. */
  749. #if STDC
  750. parse_opt(
  751.   int *ainpc,
  752.   char **inpv
  753. )
  754. #else /* NOT STDC */
  755. parse_opt( ainpc, inpv )
  756.   int *ainpc;
  757.   char **inpv;
  758. #endif /* STDC */
  759. {
  760.     /* code to be added later */
  761.     return( inpv );
  762. }
  763.  
  764. /* Read additional command line arguments: */
  765. static char **
  766. #if STDC
  767. read_cmd_lin(
  768.   int *ainpc,
  769.   char **inpv
  770. )
  771. #else /* NOT STDC */
  772. read_cmd_lin( ainpc, inpv )
  773.   int *ainpc;
  774.   char **inpv;
  775. #endif /* STDC */
  776. {
  777.   int midc;
  778.   char **midv, line[4096], *ap, *cp, c;
  779.     if(  NULL == read_w_prompt( OPprompt, line, sizeof(line) )  )
  780.         lib$stop( vaxc$errno );
  781.     midv = add_arg( (char*)NULL, &midc, (char**)NULL );
  782.     while(    (*ainpc)--  )
  783.         midv = add_arg( *(inpv++), &midc, midv );
  784.     cp = strcpy(  emalloc( strlen(line)+1 ),  line    );
  785.     do {
  786.         while(    isspace( *cp )    )
  787.             cp++;
  788.         if(  !*( ap = cp )  )
  789.             break;
  790.         while(    *cp  &&     !isspace(*cp)    )
  791.             cp++;
  792.         c = *cp;   *cp++ = '\0';
  793.         midv = add_arg( ap, &midc, midv );
  794.     } while(  c  );
  795.     *ainpc = midc;
  796.     return( midv );
  797. }
  798.  
  799. /* Prompt for a string from SYS$INPUT: */
  800. static char *
  801. #if STDC
  802. read_w_prompt(
  803.   char *prompt, /* String to prompt user with */
  804.   char *buff,    /* Pointer to buffer to store the string that is read */
  805.   int size    /* Size of *buff */
  806. )
  807. #else /* NOT STDC */
  808. read_w_prompt( prompt, buff, size )
  809.   char *prompt; /* String to prompt user with */
  810.   char *buff;    /* Pointer to buffer to store the string that is read */
  811.   int size;    /* Size of *buff */
  812. #endif /* STDC */
  813. {
  814.   desc_str( pdsc, prompt );
  815.   struct descr bdsc = { size-1, dsc$k_dtype_t, dsc$k_class_s, buff };
  816.   extern uint lib$get_command();
  817.   ushort len;
  818.   uint stat = lib$get_command( &bdsc, &pdsc, &len );
  819.     if(  !odd( stat )  ) {
  820.         errno = EIO; /* or EVMSERR? */
  821.         vaxc$errno = stat;
  822.         return( 0 );
  823.     }
  824.     buff[len] = '\0';
  825.     return( buff );
  826. }
  827.  
  828. /* Aspects of redirection common to both ">" (and variants) and "<": */
  829. static char **                /* Returns new value for `inpv'. */
  830. #if STDC
  831. redir(
  832.   int *ainpc,
  833.   char **inpv,
  834.   FILE *fp,    /* `stdin' or `stdout' */
  835.   char *io,    /* "in" or "out" */
  836.   char *tok,    /* ", `<'" or " (`>', `>>', `>&', or `>>&')" */
  837.   char *lnm,    /* logical name:  "SYS$INPUT:" or "SYS$OUTPUT:" */
  838.   char *acc    /* file access:     "r", "w", or "a" */
  839. )
  840. #else /* NOT STDC */
  841. redir( ainpc, inpv, fp, io, tok, lnm, acc )
  842.   int *ainpc;
  843.   char **inpv;
  844.   FILE *fp;    /* `stdin' or `stdout' */
  845.   char *io;    /* "in" or "out" */
  846.   char *tok;    /* ", `<'" or " (`>', `>>', `>&', or `>>&')" */
  847.   char *lnm;    /* logical name:  "SYS$INPUT:" or "SYS$OUTPUT:" */
  848.   char *acc;    /* file access:     "r", "w", or "a" */
  849. #endif /* STDC */
  850. {
  851.   uint stat = 0;    /* Assume we wouldnn't reassign `lnm'. */
  852.     if(  !**inpv  )        /* Not ">file" / "<file", must be... */
  853.         --*ainpc,  ++inpv;        /* ... "> file" / "< file". */
  854.     if(  !*inpv  ||     !**inpv  ) {
  855.         fprintf( stderr,
  856.           "Invalid null %sput redirection%s.\n", io, tok );
  857.         if(  *ainpc == 0  )    /* Fell off end of argument list: */
  858.             ++*ainpc,  --inpv;
  859.         return( inpv );
  860.     }
  861.     if(  strchr( *inpv, '*' )  ||  strchr( *inpv, '%' )
  862.      ||  strsub( *inpv, "..." )  ) {
  863.         fprintf( stderr, "Wildcards (%s) illegal in redirection%s.\n",
  864.           *inpv, tok );
  865.         return( inpv );
  866.     }
  867.     *strchr( lnm, ':' ) = '\0';    /* Remove trailing colon. */
  868.     if(  strchr( *inpv, '/' )  ||  strsub( *inpv, ".." )  ) {
  869.         if(  OPdebug  )
  870.             fprintf( stderr, "%s %s %s (%s).\n",
  871.              "Warning:  Can't reassign", lnm,
  872.              "to Un*x-style file name", *inpv );
  873.     } else {
  874.         stat = crelnm( "LNM$FILE_DEV", lnm, *inpv );
  875.         if(  OPdebug  )
  876.             sigvms( stat );
  877.     }
  878.     lnm[strlen(lnm)] = ':';        /* Restore trailing colon. */
  879.     if(  !freopen( odd(stat) ? lnm : *inpv, acc, fp )  ) {
  880.     /* if(    !( odd(stat) && freopen(lnm,acc,fp) )
  881.      &&  !freopen(*inpv,acc,fp)  ) { */
  882.         fprintf( stderr, "Can't open \"%s\" as `std%s'.\n", *inpv, io );
  883.         /* perror( *inpv ); */
  884.         exit( vaxc$errno );
  885.     }
  886.     return( inpv );
  887. }
  888.  
  889. /* Redirects `stdin': */
  890. static char **
  891. #if STDC
  892. redirin(
  893.   int *ainpc,
  894.   char **inpv
  895. )
  896. #else /* NOT STDC */
  897. redirin( ainpc, inpv )
  898.   int *ainpc;
  899.   char **inpv;
  900. #endif /* STDC */
  901. {
  902.     ++*inpv;    /* Skip over the '<'. */
  903.     return(redir( ainpc, inpv, stdin, "in", ", `<'", "SYS$INPUT:", "r" ));
  904. }
  905.  
  906. /* Redirects `stdout': */
  907. static char **
  908. #if STDC
  909. redirout(
  910.   int *ainpc,
  911.   char **inpv
  912. )
  913. #else /* NOT STDC */
  914. redirout( ainpc, inpv )
  915.   int *ainpc;
  916.   char **inpv;
  917. #endif /* STDC */
  918. {
  919.   bool err = 0;        /* Assume not ">&" nor ">>&". */
  920.   char *acc = "w";    /* Assume ">" (write) not ">>" (append). */
  921.     if(  '>' == *++*inpv  )        /* Append to output file: */
  922.         ++*inpv,  *acc = 'a';
  923.     if(  '&' == **inpv  )        /* Redirect `stderr' as well: */
  924.         ++*inpv,  err = 1;
  925.     inpv = redir( ainpc, inpv, stdout, "out",
  926.       " (`>', `>>', `>&', or `>>&')", "SYS$OUTPUT:", acc );
  927.     /* The following is harmless if redir() failed: */
  928.     if(  err  ) {
  929.         if(  !strchr( *inpv, '/' )  &&    !strsub( *inpv, ".." )    ) {
  930.           uint stat = crelnm( "LNM$FILE_DEV", "SYS$ERROR", *inpv );
  931.             if(  OPdebug  )
  932.                 sigvms( stat );
  933.         }
  934.         stderr = stdout;    /* VAX-C specific method. */
  935.     }
  936.     return( inpv );
  937. }
  938.  
  939. /* Signals any non-boring condition values so that error/warning messages
  940.  * will be displayed. */
  941. static void
  942. #if STDC
  943. sigvms(
  944.   uint stat
  945. )
  946. #else /* NOT STDC */
  947. sigvms( stat )
  948.   uint stat;
  949. #endif /* STDC */
  950. {
  951.   extern void lib$signal();
  952.     if(  ( stat & 0xffff ) == 1 )
  953.         return;        /* Boring status message; skip it. */
  954.     lib$signal( stat );
  955. }
  956.  
  957. /* Returns the position of a substring within a string.     Should be replaced by
  958.  * strstr() when DEC provides one. */
  959. static char *
  960. #if STDC
  961. strsub(
  962.   char *str,
  963.   char *sub
  964. )
  965. #else /* NOT STDC */
  966. strsub( str, sub )
  967.   char *str;
  968.   char *sub;
  969. #endif /* STDC */
  970. {
  971.   register char *fp = sub;    /* Points to character we hope to Find next */
  972.   char *sp = strchr(str,*fp);    /* Points to current Starting character */
  973.   register char *cp = sp;    /* Points to character currently Comparing */
  974.     while(    sp  ) {
  975.         while(    *fp  &&     *fp == *cp  )
  976.             ++fp, ++cp;
  977.         if(  !*fp  )
  978.             return( sp );    /* We found it */
  979.         fp = sub;        /* Start the search over again */
  980.         cp = sp = strchr(sp+1,*fp);    /* were we left off last time */
  981.     }
  982.     return( 0 );
  983. }
  984. #ifdef TEST
  985.  
  986. /* Displays a string to `stdout', making all control and meta characters
  987.  * printable unambigously. */
  988. static void
  989. #if STDC
  990. dump(
  991.   char *str
  992. )
  993. #else /* NOT STDC */
  994. dump( str )
  995.   char *str;
  996. #endif /* STDC */
  997. {
  998. # define META '`'    /* Show 'a'+'\200' as "`a" */
  999. # define CTRL '^'    /* Show '\001' as "^A" */
  1000. # define BOTH '~'    /* Show '\201' as "~A" */
  1001. # define QOTE '~'    /* Show '`' as "~`", '^' as "~^", and '~' as "~~" */
  1002. # define DEL '\177'
  1003. # define uncntrl(c)    ( DEL==c ? '?' : c + '@' )
  1004.   static char spec[] = { META, CTRL, BOTH, QOTE, 0 };
  1005.     while(    *str  ) {
  1006.         switch(     (!!iscntrl(*str)) + 2 * (!isascii(*str))  ) {
  1007.           case 0: /* Normal */
  1008.             if(  strchr( spec, *str )  )
  1009.                 putchar( QOTE );
  1010.             putchar( *str );
  1011.             break;
  1012.           case 1: /* Control */
  1013.             putchar( CTRL );
  1014.             putchar( uncntrl(*str) );
  1015.             break;
  1016.           case 2: /* Meta */
  1017.             putchar( META );
  1018.             putchar( toascii(*str) );
  1019.             break;
  1020.           case 3: /* Both */
  1021.             putchar( BOTH );
  1022.             putchar( uncntrl(toascii(*str)) );
  1023.             break;
  1024.         }
  1025.         ++str;
  1026.     }
  1027. }
  1028.  
  1029. int
  1030. #if STDC
  1031. main(
  1032.   int argc,
  1033.   char **argv
  1034. )
  1035. #else /* NOT STDC */
  1036. main( argc, argv )
  1037.   int argc;
  1038.   char **argv;
  1039. #endif /* STDC */
  1040. {
  1041.     int cnt;
  1042.     extern char **cmd_lin();
  1043.  
  1044.     argv = cmd_lin( "", &argc, argv );
  1045.     printf( "%d argument%s%s\n", argc, 1==argc ? "" : "s", argc ? ":" : "." );
  1046.     for(  cnt = 0; *argv; ++argv )
  1047.     {
  1048.     printf( "%5d: `", ++cnt );
  1049.     dump( *argv );
  1050.     printf( "'\n" );
  1051.     }
  1052.     exit(EXIT_SUCCESS);
  1053.     return(0);
  1054. }
  1055. #endif /* TEST */
  1056.  
  1057. #endif /* VMS */
  1058.